occamsrazor-validator
This is a validator library with a very specific goal. Identify if a value matches some criteria using (duck typing)[https://en.wikipedia.org/wiki/Duck_typing] and assigning a score to the match.
Given the goal it is not a full fledged schema validator library. For this reason:
- It identifies what an object "has" rather than what it "is"
- An object passing the validation returns a "validationResult". This object has a value, based on how many validation steps has passed.
It is a part of occamsrazor (https://github.com/sithmel/occamsrazor.js) that uses this library for picking the right function for a specific set of arguments.
Importing the library
var validator = require('occamsrazor-validator');
What is a validators
Ultimately a validator is a function. When it runs against an object, it returns null or a score (wrapped in a validationResult for convenience).
Null means that an object doesn't fit in the validator's constraints.
The score represent how well the object fits (its specificity). For example:
var isAnything = validator();
"validator()" creates the simplest validator. It matches everything with score 0:
isAnything('hello').value();
isAnything({width: 10}).value();
You can chain a function to create a more strict validation:
var hasWheels = isAnything.match(function (obj){
return 'wheels' in obj;
});
So for example, the score of this new validator will be 1:
hasWheels({wheels: 4}).value();
hasWheels({feet: 2});
You can go on having a more specific validator:
var hasWheelsAndWings = hasWheels.match(function (obj){
return 'wings' in obj;
});
Every validator has a function "score" that returns its specificity:
isAnything.score()
hasWheels.score()
hasWheelsAndWings.score()
In order to write validators you can use duck typing, type checking or whatever check you want to use:
var has_wings = validator().match(function (obj){
return 'wings' in obj;
});
var is_a_car = validator().match(function (obj){
return Car.prototype.isPrototypeOf(obj);
});
var is_year = validator().match(function (obj){
var re = /[0-9]{4}/;
return !!obj.match(re);
});
The "match" method allows to extend a validator using a terse syntax. You have already seen that it can take a function as argument.
You can also pass a string or a regular expression for matching a string:
var is_hello = validator().match('hello');
var contains_nuts = validator().match(/nut/);
is_hello('hello');
contains_nuts('hazelnut');
Or numbers:
var is_ten = validator().match(10);
is_ten(10);
It works for booleans and null in the same way.
If you pass an array it will match with any element of an input array with its content:
var has_1_2 = validator().match([1, 2]);
Finally you can perform deep property checking using an object and combining the previous checks:
var has_width_and_height_10 = validator().match({width: 10, height: 10});
var has_center = validator().match({center: {x: undefined, y: undefined}});
var recipe_has_nuts = validator().match({recipe: {ingredients: /nuts/}});
var is_heavy = validator().match({weight: function (obj){return obj > 100}});
There are other 3 helpers available::
var is_prototype_rect = validator().isPrototypeOf(rect.prototype);
var is_instance_rect = validator().isInstanceOf(Rect);
var has_attr = validator().has('width', 'height');
If you need a custom validator you can extend the object validator.shortcut_validators::
validator.shortcut_validators.isSquare = function (){
return function (obj){
return 'width' in obj && 'height' in obj && obj.width === obj.height;
};
};
Of course you can combine all the methods we have seen so far::
var is_instance_a_square = validator()
.isInstanceOf(Rect)
.has('width', 'height')
.isSquare();
Combine validators
You might want to match a group of values. You can do it combine as many validators you want:
var isNumber = validator().match(function (n) {
return typeof n === 'number';
});
var is5 = isNumber.match(5);
var is8 = isNumber.match(8);
var v = combineValidators(isNumber, is5, is8);
and then trying to make it match:
v(1, 5, 8).value();
If all values match, the validator will return a validationResult with value [1, 2, 2].
The elements of the array are the values of the respective validators.
If one of them doesn't match the result will be null:
v(1, 5, 5);
When the value returned is an array it is compared in this way (alphabetically):
[2, 3, 4] > [2, 2, 5]
[1] < [1, 2]
[2] > [1, 9, 5]
Sort and compare results
The result validator object has an useful property. It can be sorted and compared (greater than, lesser than) as it was a basic js type. You can use the output of the toString attribute to compare for equality:
r0 > r1
var results = [r0, r1, r2, r3];
r.sort();
r0.toString() === r1.toString()
Syntax
Validator function
Syntax:
validator();
Returns a generic validator. It will validate every object with score 0.
validator().score
Syntax:
a_validator.score();
Returns the score returned by this validator. It can be useful for debugging or introspection.
validator().important
Syntax:
a_validator.important([n]);
It bumps the score by n (default to 64).
validator().match
Add a check to the validator, using an expressive syntax.
Syntax:
var validator = validator().match(function);
var validator = validator().match(string);
var validator = validator().match(null);
var validator = validator().match(boolean);
var validator = validator().match(number);
var validator = validator().match(regular_expression);
var validator = validator().match([items]);
var validator = validator().match({propName1: "string", propName2: {propName3: "string"}});
The last two forms allow to perform the validation check recursively, walking the properties of the object/array.
In a property is undefined the value will match any value.
For example:
var hasCenterX = validator().match({center: {x: undefined}});
var hasCenterX10 = validator().match({center: {x: "10"}});
var hasCenter5or10 = validator().match({center: {x : function (c){
return c === "5" || c === "10";
}}});
validator().isPrototypeOf
Check if an object is a prototype of another.
Syntax:
var validator = validator().isPrototypeOf(obj);
validator().instanceOf
Check if an object is an instance of a constructor.
Syntax:
var validator = validator().instanceOf(ContructorFunc);
validator().has
Check if an object has attributes with a specific names.
Syntax:
var validator = validator().has(attr1, attr2, ...);
validator.shortcut_validators
It is an object where you can add your shortcut validators.
"match" and "isPrototypeOf" are added here but you can add your own if you need.